#include "GUIMenu.h"
#include "IRenderer.h"
#include "OnMouseLeftDownEvent.h"
#include "OnMouseLeftUpEvent.h"

#define PADDING				2
#define OBJECTWIDTH			80
#define OBJECTHEIGHT		10
#define OBJECTHEIGHTOFFSET	(OBJECTHEIGHT-12)/2
#define INDENT				10

GUIMenu::GUIMenu()
{
	m_fontColor = 0x00000000;
	m_font = HashedString("Arial");
	m_visible = true;
	m_enabled = true;
	m_dimensions = Maths::Point<unsigned int>(OBJECTWIDTH, OBJECTHEIGHT);
}
void GUIMenu::Paint()
{
	if (m_visible)
	{
		int totalHeight = 0;
		Maths::Matrix transform;

		if (m_title.size() > 0)
		{
			// Render Background
			transform.Translate(m_location.X, m_location.Y, 0.0f);
			transform.Scale(m_dimensions.X, m_dimensions.Y, 1.0f);
		
			Renderer->SetColor(0xFFDDDDDD);
			Renderer->PushTexture(m_background);
			Renderer->PushModelViewMatrix(transform);
			Renderer->Render(*(m_shape.getShape()));
			Renderer->PopModelViewMatrix();
			Renderer->PopTexture();

			// Render title
			// OBJECTHEIGHTOFFSET centers text
			Renderer->PrintFont(m_font, m_fontColor, m_parentLocation.X + m_location.X + 4, m_parentLocation.Y + m_location.Y + OBJECTHEIGHTOFFSET, m_title.c_str());
		
			// Render MenuItems
			transform.Identity();
			transform.Translate(m_location.X + INDENT, m_location.Y + OBJECTHEIGHT, 0.0f);		// Add OBJECTHEIGHT to Y for title
			Renderer->PushModelViewMatrix(transform);
			
			totalHeight = PADDING;
		} else
		{
			// Render MenuItems
			transform.Identity();
			transform.Translate(m_location.X, m_location.Y, 0.0f);		// Add OBJECTHEIGHT to Y for title
			Renderer->PushModelViewMatrix(transform);
		
			totalHeight = 0;
		}
		
		int indent = m_title.size() > 0 ? INDENT : 0;
		for (GUIMenuItem::Vector_t::const_iterator it = m_menuItems.begin(); it != m_menuItems.end(); ++it)
		{
			if ((*it)->Visible())
			{
				(*it)->Location(Maths::Point<unsigned int>(indent, totalHeight));
				(*it)->Paint();
				totalHeight += OBJECTHEIGHT + PADDING + ((*it)->Open() ? (*it)->TotalHeight() : 0);
			}
		}

		Renderer->PopModelViewMatrix();
	}
}
void GUIMenu::Title( std::string& title )
{
	m_title = title;
}
std::string GUIMenu::Title() const
{
	return m_title;
}
void GUIMenu::Font( std::string& font )
{
	m_font = HashedString(font);
}
void GUIMenu::Font( HashedString& font )
{
	m_font = font;
}
HashedString GUIMenu::Font() const
{
	return m_font;
}
void GUIMenu::FontColor( unsigned int color )
{
	m_fontColor = color;
}
unsigned int GUIMenu::FontColor() const
{
	return m_fontColor;
}
void GUIMenu::Background( std::string& background )
{
	m_background = HashedString(background);
}
void GUIMenu::Background( HashedString& background )
{
	m_background = background;
}
HashedString GUIMenu::Background() const
{
	return m_background;
}
bool GUIMenu::ReceiveEvent( IEvent& event )
{
	if (m_enabled && m_visible)
	{
		if (event.Type() == OnMouseLeftDownEvent::type)
		{
			OnMouseLeftDownEvent& mouseEvent = static_cast<OnMouseLeftDownEvent&>(event);
			int x = mouseEvent.Coords().X;
			int y = mouseEvent.Coords().Y;
			int absX = m_location.X + m_parentLocation.X;
			int absY = m_location.Y + m_parentLocation.Y;
			int greatestWidth = OBJECTWIDTH;
			int totalHeight = m_title.size() > 0 ? PADDING : 0;
			int titleHeight = m_title.size() > 0 ? OBJECTHEIGHT : 0;
			int indent = m_title.size() > 0 ? INDENT : 0;
			// for every menu object
			for (GUIMenuItem::Vector_t::const_iterator it = m_menuItems.begin(); it != m_menuItems.end(); ++it)
			{
				totalHeight += OBJECTHEIGHT + PADDING + ((*it)->Open() ? (*it)->TotalHeight() : 0);			// add OBJECTHEIGHT for title
				if ((*it)->Open() && greatestWidth < (*it)->TotalWidth())
					greatestWidth = (*it)->TotalWidth();
			}

			if ((x > absX + indent) && (x < absX + greatestWidth + indent) &&
				(y > absY + titleHeight) && (y < absY + totalHeight))						// not title clicked
			{
				for (GUIMenuItem::Vector_t::iterator it = m_menuItems.begin(); it != m_menuItems.end(); ++it)
				{
					if ((*it)->ReceiveEvent(event))
						return true;
				}
			}
		} else if (event.Type() == OnMouseLeftUpEvent::type)
		{
			OnMouseLeftUpEvent& mouseEvent = static_cast<OnMouseLeftUpEvent&>(event);
			int x = mouseEvent.Coords().X;
			int y = mouseEvent.Coords().Y;
			int absX = m_location.X + m_parentLocation.X;
			int absY = m_location.Y + m_parentLocation.Y;
			int greatestWidth = OBJECTWIDTH;
			int totalHeight = m_title.size() > 0 ? PADDING : 0;
			int titleHeight = m_title.size() > 0 ? OBJECTHEIGHT : 0;
			int indent = m_title.size() > 0 ? INDENT : 0;
			// for every menu object
			for (GUIMenuItem::Vector_t::const_iterator it = m_menuItems.begin(); it != m_menuItems.end(); ++it)
			{
				totalHeight += OBJECTHEIGHT + PADDING + ((*it)->Open() ? (*it)->TotalHeight() : 0);			// add OBJECTHEIGHT for title
				if ((*it)->Open() && greatestWidth < (*it)->TotalWidth())
					greatestWidth = (*it)->TotalWidth();
			}

			if ((x > absX + indent) && (x < absX + greatestWidth + indent) &&
				(y > absY + titleHeight) && (y < absY + totalHeight))						// not title clicked
			{
				for (GUIMenuItem::Vector_t::iterator it = m_menuItems.begin(); it != m_menuItems.end(); ++it)
				{
					if ((*it)->ReceiveEvent(event))
						return true;
				}
			}
		}
	}
	return false;
}
void GUIMenu::AddMenuItem( Pointer<GUIMenuItem> menuItem )
{
	m_menuItems.push_back(menuItem);
	if (m_title.size() > 0)				// visible header?
		menuItem->ParentLocation(Maths::Point<unsigned int>(m_location.X + m_parentLocation.X, m_location.Y + m_parentLocation.Y + OBJECTHEIGHT + OBJECTHEIGHTOFFSET));
	else								// no
		menuItem->ParentLocation(Maths::Point<unsigned int>(m_location.X + m_parentLocation.X, m_location.Y + m_parentLocation.Y));
	menuItem->Parent(m_parent);
}
void GUIMenu::Location( Maths::Point<unsigned int>& location )
{
	m_location = location;

	for (GUIMenuItem::Vector_t::iterator it = m_menuItems.begin(); it != m_menuItems.end(); ++it)
	{
		if (m_title.size() > 0)				// visible header?
			(*it)->ParentLocation(Maths::Point<unsigned int>(m_location.X + m_parentLocation.X, m_location.Y + m_parentLocation.Y + OBJECTHEIGHT + OBJECTHEIGHTOFFSET));
		else								// no
			(*it)->ParentLocation(Maths::Point<unsigned int>(m_location.X + m_parentLocation.X, m_location.Y + m_parentLocation.Y));
	}
}
void GUIMenu::ParentLocation( Maths::Point<unsigned int>& location )
{
	m_parentLocation = location;
	for (GUIMenuItem::Vector_t::iterator it = m_menuItems.begin(); it != m_menuItems.end(); ++it)
	{
		if (m_title.size() > 0)				// visible header?
			(*it)->ParentLocation(Maths::Point<unsigned int>(m_location.X + m_parentLocation.X, m_location.Y + m_parentLocation.Y + OBJECTHEIGHT + OBJECTHEIGHTOFFSET));
		else								// no
			(*it)->ParentLocation(Maths::Point<unsigned int>(m_location.X + m_parentLocation.X, m_location.Y + m_parentLocation.Y));
	}
}

void GUIMenu::ClearMenuItems()
{
	m_menuItems.clear();
}